package listen;

import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.Iterator;

import com.google.gson.JsonObject;
import com.google.gson.JsonParser;

import users.TaskData;
import users.GroupTask;

import logging.LogWriter;

public class ServerAction {
	private JsonObject json;
	private final LogWriter serverLog = new LogWriter();
	private AccountDatabase db;
	
	public ServerAction(String input, AccountDatabase db) {
		json = new JsonParser().parse(input).getAsJsonObject();
		this.db = db;
	}
	
	public ServerAction (JsonObject json, AccountDatabase db) {
		this.json = json;
		this.db = db;
	}
	
	public String Action() {
		String sendText = "{\"userName\":\"ME\", \"option\":\"FAILED\", \"password\":\"anything\"}";
		
		try {
			String requestCommand = "request" + json.getAsJsonPrimitive("option").getAsString();
			ServerAction object = new ServerAction(json, db);
			Method method =	Class.forName("listen.ServerAction").getMethod(requestCommand, String.class);
			Object returnObject = method.invoke(object, "String Input");
			sendText = (String)returnObject;
		} catch (IllegalAccessException e) {
			serverLog.log("Improper Access by method call: " + e); 
		} catch	(IllegalArgumentException e) {
			serverLog.log("Wrong argument for method call: " + e);
		} catch	(InvocationTargetException e) {
			serverLog.log("Invocation target fault: " + e); 
		} catch	(ClassNotFoundException e) {
			serverLog.log("Class not found: " +	e);
		} catch (NoSuchMethodException e) {
			serverLog.log("Missing method called: " + e);
		}
		
		return sendText;
	}
	
	/*
	 * These methods are all for handling client requests. The format: request + <client request>
	 * e.g. request + UPDATE = requestUPDATE()
	 */
	public String requestLOGIN(String input) {
		serverLog.log("--Login Requested.--");
		String user = json.getAsJsonPrimitive("userName").getAsString();
		String pwd = json.getAsJsonPrimitive("password").getAsString();

		if (db.getValidUserAccounts().containsKey(user)) {
			serverLog.log("User (" + user + ") attempting to login.");
			if (db.getValidUserAccounts().get(user).equals(pwd)) {
				serverLog.log("User (" + user + ") logged in.");
			} else {
				serverLog.log("User (" + user + ") failed to login.");
				//serverLog.log("Password " + pwd + " != " + db.getValidUserAccounts().get(name));
				return "{\"userName\":\"" + user + "\", \"option\":\"FAILED\", \"password\":\"" + pwd + "\"}";
			}
		} else {
			serverLog.log("New User: " + user);
			db.addUserAccount(user, pwd);
			return "{\"userName\":\"" + user + "\", \"option\":\"NEW\", \"password\":\"" + pwd + "\"}";
		}
		System.out.println ("Account = " + db.getAccountCounter());
		return "{\"userName\":\"" + user + "\", \"option\":\"GOOD\", \"password\":\"" + pwd + "\"}";
	}
	
	public String requestUPDATE(String input) {
		serverLog.log("--User Update Requested.--");
		String user = json.getAsJsonPrimitive("userName").getAsString();
		String data = db.getUserList().get(user).getTasksToString();
		for (int x = 0; x < db.getGroup().size(); x++) {
			if (db.getGroup().get(x).isMember(user)) {
				serverLog.log("Found, " + user + " member of group task id "	+ db.getGroup().get(x).getGroupTaskID());
				data += db.getGroup().get(x).getTask().toString();
			}
		}
		return "{\"userName\":\"" + json.getAsJsonPrimitive("userName").getAsString() + "\", \"option\":\"GOOD\", \"password\":\"" + json.getAsJsonPrimitive("password").getAsString() + "\", \"data\":\""+ data + "\"}";
	}

	private String requestADD(String input) {
		serverLog.log("--User Added Task--");
		String user = json.getAsJsonPrimitive("userName").getAsString();
		db.getUserList().get(user).addTask(new TaskData(json.getAsJsonPrimitive("data").getAsString()));
		
		return "{\"userName\":\"" + json.getAsJsonPrimitive("userName").getAsString() + "\", \"option\":\"GOOD\", \"password\":\"" + json.getAsJsonPrimitive("password").getAsString() + "\"}";
	}

	private String requestEDIT(String input) {
		serverLog.log("--User Editing Task--");
		String user = json.getAsJsonPrimitive("userName").getAsString();
		String data = json.getAsJsonPrimitive("data").getAsString();
				
		TaskData task = new TaskData(data);
		if (task.getGroupID() < 0) {
			if (db.getUserList().get(user).editTask(task)) {
				serverLog.log("--Edited User Task--");
				serverLog.log("User (" + user + ") edited task " + task.getTaskId() + ": " + task.getTitle());
			} else {
				serverLog.log("Error: Failed to update User (" + user + ") edit task " + task.getTaskId() + ": " + task.getTitle());
			}
		} else {
			for(int x = 0; x < db.getGroup().size(); x++) {
				if(db.getGroup().get(x).getGroupTaskID() == task.getGroupID()) {
					db.getGroup().get(x).editTask(task);
					serverLog.log("--Group Task Edited--");
					serverLog.log("User (" + user + ") edited group task " + task.getGroupID() + ": " + task.getTitle());
					return "{\"userName\":\"" + json.getAsJsonPrimitive("userName").getAsString() + "\", \"option\":\"GOOD\", \"password\":\"" + json.getAsJsonPrimitive("password").getAsString() + "\"}";
				}
			}
			serverLog.log("Error: Failed to edit group task " + task.getGroupID() + ": "	+ task.getTitle());
		}
		
		return "{\"userName\":\"" + json.getAsJsonPrimitive("userName").getAsString() + "\", \"option\":\"GOOD\", \"password\":\"" + json.getAsJsonPrimitive("password").getAsString() + "\"}";
	}

	private String requestDELETE(String input) {
		// System.out.println("In Delete: " + line);
		// for(int x = 0; x < line.length; x++)
		// System.out.println("In Delete: " + line[x]);

		serverLog.log("--User Deleting Task--");
		String user = json.getAsJsonPrimitive("userName").getAsString();
		String data = json.getAsJsonPrimitive("data").getAsString();
		
		int taskID = Integer.valueOf(data);
		db.getUserList().get(user).getTaskList().remove(db.getUserList().get(user).findTaskIDLocation(taskID));
		
		return "{\"userName\":\"" + json.getAsJsonPrimitive("userName").getAsString() + "\", \"option\":\"GOOD\", \"password\":\"" + json.getAsJsonPrimitive("password").getAsString() + "\"}";
	}
	
	private String requestGROUPDELETE(String input) {
		serverLog.log("--User Deleting Group Task--");
		String user = json.getAsJsonPrimitive("userName").getAsString();
		String data = json.getAsJsonPrimitive("data").getAsString();

		int groupID = Integer.valueOf(data);
		int index = 0;
		
		serverLog.log("User " + user + " requesting removal from group task " + groupID + ".");
		while((index < db.getGroup().size()) && (db.getGroup().get(index).getGroupTaskID() != groupID)) {
			index++;
		}
		
		if(db.getGroup().get(index).removeMember(user)) {
			serverLog.log("User " + user + " removed from group task " + groupID + ".");
		} else {
			serverLog.log("Failed to remove " + user + " from group task " + groupID + ".");
		}
		
		// Remove group task from list if no more members are attached to task.
		if(db.getGroup().get(index).noMembers()) {
			db.getGroup().remove(index);
			serverLog.log("Group task " + groupID + " has no members. Deleting.");
		}
		
		return "{\"userName\":\"" + json.getAsJsonPrimitive("userName").getAsString() + "\", \"option\":\"GOOD\", \"password\":\"" + json.getAsJsonPrimitive("password").getAsString() + "\"}";
	}

	private String requestGROUPUSERS(String input) {
		serverLog.log("--Requesting All Group Members--");
		String data = json.getAsJsonPrimitive("data").getAsString();
		
		int index = 0;
		int groupID = Integer.valueOf(data);
		serverLog.log("Requesting group " + groupID + " members.");
		while((index < db.getGroup().size()) && (db.getGroup().get(index).getGroupTaskID() != groupID)) {
			index++;
		}
		serverLog.log("Group " + groupID + " found.");
		data = db.getGroup().get(index).getMembersToString();
		
		return "{\"userName\":\"" + json.getAsJsonPrimitive("userName").getAsString() + "\", \"option\":\"GOOD\", \"password\":\"" + json.getAsJsonPrimitive("password").getAsString() + "\", \"data\":\""+ data + "\"}";
	}
	/*
	private String requestMEMBERS(String[] line) {
		int index = 0;
		int groupID = Integer.valueOf(line[1]);;
		serverLog.log("Requesting group " + groupID + " members for viewing.");
		while((index < group.size()) && (group.get(index).getGroupTaskID() != groupID)) {
			index++;
		}
		serverLog.log("Group " + groupID + " found.");
		return group.get(index).getMembersToStringOneLine();
	}
	*/
	
	private String requestALLUSERS(String input) {
		serverLog.log("--Requesting All Valid Users--");
	
		String data = "";
		Iterator user = db.getValidUserAccounts().keySet().iterator();
		
		while(user.hasNext()) {
			data += user.next() + "\n";
		}
		
		return "{\"userName\":\"" + json.getAsJsonPrimitive("userName").getAsString() + "\", \"option\":\"GOOD\", \"password\":\"" + json.getAsJsonPrimitive("password").getAsString() + "\", \"data\":\""+ data + "\"}";
	}
	
	private String requestSAVEGROUPUSERS(String input) {
		serverLog.log("--Saving Group Members--");
		String data = json.getAsJsonPrimitive("data").getAsString();
		int groupID = Integer.valueOf(data);
		int index = 0;
		
		serverLog.log("Updating group members for group task " + groupID + ".");
		
		while((index < db.getGroup().size()) && (db.getGroup().get(index).getGroupTaskID() != groupID)) {
			index++;
		}
		
		String[] members = json.getAsJsonPrimitive("members").getAsString().split("<CR>");
		db.getGroup().get(index).setMembers(members);
		
		return "{\"userName\":\"" + json.getAsJsonPrimitive("userName").getAsString() + "\", \"option\":\"GOOD\", \"password\":\"" + json.getAsJsonPrimitive("password").getAsString() + "\"}";
	}
	
	private String requestNEWGROUP(String input) {
		serverLog.log("--Creaing New Group Task--");
		String user = json.getAsJsonPrimitive("userName").getAsString();

		db.createGroup(user);

		return "{\"userName\":\"" + json.getAsJsonPrimitive("userName").getAsString() + "\", \"option\":\"GOOD\", \"password\":\"" + json.getAsJsonPrimitive("password").getAsString() + "\"}";

	}
}
